package com.ly.service.user;

import com.google.common.collect.Lists;
import com.ly.base.LoginUserUtil;
import com.ly.base.UserStatus;
import com.ly.entity.Role;
import com.ly.entity.User;
import com.ly.repository.RoleRepository;
import com.ly.repository.UserRepository;
import com.ly.service.IUserService;
import com.ly.service.ServiceMultiResult;
import com.ly.service.ServiceResult;
import com.ly.web.dto.HouseDTO;
import com.ly.web.dto.UserDTO;
import com.ly.web.form.DatatableUserSearch;
import com.ly.web.form.HouseForm;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.access.method.P;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author ：LY
 * @date ：Created in 2020/11/8 20:04
 * @modified By：
 */
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private ModelMapper modelMapper;

    private final Md5PasswordEncoder passwordEncoder = new Md5PasswordEncoder();

    @Override
    public User findUserByName(String userName) {
        User user = userRepository.findByName(userName);

        if (user == null) {
            return null;
        }
        //调用dao的方法实现，dao的方法名必须写对，否则将会出现编译错误
        //获取此用户的权限信息
        List<Role> roles = roleRepository.findRolesByUserId(user.getId());
        if (roles == null || roles.isEmpty()) {
            throw new DisabledException("权限非法");
        }

        List<GrantedAuthority> authorities = new ArrayList<>();
        roles.forEach(role -> authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName())));
        user.setAuthorityList(authorities);
        return user;
    }

    @Override
    public ServiceResult<UserDTO> findById(Long adminId) {
        User one = userRepository.findOne(adminId);
        if (one == null){
            return ServiceResult.notFound();
        }
        UserDTO userDTO = modelMapper.map(one,UserDTO.class);

        return ServiceResult.of(userDTO);
    }

    @Override
    public User findUserByTelephone(String telephone) {
       User user = userRepository.findUserByPhoneNumber(telephone);
        if (user == null){
            return null;
        }
       List<Role> roles  =  roleRepository.findRolesByUserId(user.getId());
       if (roles == null|| roles.isEmpty()){
           throw new DisabledException("权限非法");
       }

       List<GrantedAuthority> authorities = new ArrayList<>();
       roles.forEach(role -> authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName())));
       user.setAuthorityList(authorities);
        return user;
    }


    @Override
    @Transactional
    public User addUserByPhone(String telephone) {
        User user = new User();
        user.setPhoneNumber(telephone);
        user.setName(telephone.substring(0,3)+"****"+telephone.substring(7,telephone.length()));
        Date now = new Date();
        user.setCreateTime(now);
        user.setLastLoginTime(now);
        user.setLastUpdateTime(now);
         user = userRepository.save(user);
        Role role = new Role();
        role.setName("USER");
        role.setUserId(user.getId());
        roleRepository.save(role);
        user.setAuthorityList(Lists.newArrayList(new SimpleGrantedAuthority("ROLE_USER")));
        return user;
    }

    @Override
    @Transactional
    public ServiceResult modifyUserProfile(String profile, String value) {
        Long userId = LoginUserUtil.getLoginUserId();
        if (profile == null||profile.isEmpty()){
            return new ServiceResult(false,"属性不可以为空");
        }
        switch (profile){
            case "name":
                userRepository.updateUsername(userId,value);
                break;
            case "email":
                userRepository.updateEmail(userId,value);
                break;
            case "password":
                userRepository.updatePassword(userId,this.passwordEncoder.encodePassword(value,userId));
                break;
                default:
                    return new ServiceResult(false,"不支持的属性");
        }
        return ServiceResult.success();
    }
    /**
     * 用户浏览主要方法，主要是两个类 一个排序分页的Pageable 一个是查询对象Specification.
     * @param searchBody
     * @return
     */
    @Override
    public ServiceMultiResult<UserDTO> adminUserQuery(DatatableUserSearch searchBody) {
        List<UserDTO> userDTOS = new ArrayList<>();
        //searchBody.getDirection())指定是升序还是降序，后面那个字段指定按什么排序
        Sort sort = new Sort(Sort.Direction.fromString(searchBody.getDirection()),searchBody.getOrderBy());
        //获取当前是第几页
        int page  = searchBody.getStart()/searchBody.getLength();
        //查询对象  第一个参数第几页 第二 一页多长 第三排序
        Pageable pageable = new PageRequest(page,searchBody.getLength(),sort);
        /**
         * root    ：Root接口，代表查询的根对象，可以通过root获取实体中的属性
         * query   ：代表一个顶层查询对象，用来自定义查询
         * cb      ：用来构建查询，此对象里有很多条件方法
         *
         */
        //对参数进行一些封装，进行各种维度的查询操作
        Specification<User> specification = (root, query, cb) ->{
            //排除掉被删除的用户  3
            Predicate predicate =  cb.notEqual(root.get("status"), UserStatus.DELETED.getValue());

            if (searchBody.getUserId() != null){
                if(LoginUserUtil.checkTelephone(searchBody.getUserId())){
                    predicate  =cb.and(predicate,cb.like(root.get("phoneNumber"),"%"+searchBody.getUserId()+"%"));
                }else {
                    predicate  =cb.and(predicate,cb.like(root.get("name"),"%"+searchBody.getUserId()+"%"));
                }

            }
            return predicate;
        };
        //通过内置的findAll方法，传入一个查询对象和一个排序分页对象，返回Page
        Page<User> users = userRepository.findAll(specification,pageable);
        users.forEach(user -> {
            UserDTO userDTO = modelMapper.map(user,UserDTO.class);
            userDTOS.add(userDTO);
        });
        return new ServiceMultiResult<>(users.getTotalElements(),userDTOS);
    }
    @Override
    @Transactional
    public ServiceResult updateStatus(Long id, int value) {
        User user = userRepository.findOne(id);


        if (user == null){
            return  ServiceResult.notFound();
        }
        List<Role> rolesByUserId = roleRepository.findRolesByUserId(id);
        boolean flag = false;
        for (Role role : rolesByUserId){
            if (role.getName().equals("ADMIN")){
                flag=true;
            }
        }
        if (flag){
            return  new ServiceResult(false,"无法更改管理员状态");
        }

        if (user.getStatus() == value){
            return  new ServiceResult(false,"状态未发生变化");
        }
        if (user.getStatus() == UserStatus.DELETED.getValue()){
            return new ServiceResult(false,"已删除的资源不允许操作");
        }
        userRepository.updateStatus(user.getId(),value);

        return ServiceResult.success();
    }


    @Override
    public ServiceResult<UserDTO> findCompleteOne(Long id) {
        User user = userRepository.findOne(id);
        if ( user == null){
            return ServiceResult.notFound();
        }
        List<Role> rolesByUserId = roleRepository.findRolesByUserId(id);
        if (rolesByUserId == null){
            return ServiceResult.notFound();
        }
        UserDTO userDTO = modelMapper.map(user, UserDTO.class);
        userDTO.setRoleName(rolesByUserId.get(0).getName());
        return ServiceResult.of(userDTO);
    }

    @Override
    @Transactional
    public ServiceResult update(UserDTO userDTO) {
        User user = userRepository.findOne(userDTO.getId());
        if (user == null){
            return ServiceResult.notFound();
        }
        List<Role> rolesByUserId = roleRepository.findRolesByUserId(userDTO.getId());
        Role role = rolesByUserId.get(0);
        if (!role.getName().equals(userDTO.getRoleName())) {
            role.setName(userDTO.getRoleName());
            roleRepository.save(role);
        }
        userRepository.save(user);
        return ServiceResult.success();
    }

}
